# -*- coding: utf-8 -*-
"""
******* 文档说明 ******

# 当前项目: MovieLens
# 创建时间: 2020-10-10  15:57
# 开发作者: Vincent
# 版    本: V1.0
"""
import os, sys
import numpy as np
import pandas as pd
import lightgbm as lgb
import category_encoders as ce
from sklearn.metrics import roc_auc_score, log_loss

print("System   version:  {}".format(sys.version))
print("LightGBM version:  {}".format(lgb.__version__))
print('numpy  Version: {}'.format(np.__version__))
print('pandas Version: {}'.format(pd.__version__))

#  criteo 数据集
filepath = './data/dac/dac_sample.txt'

nume_cols = ["I" + str(i) for i in range(1, 14)]
cate_cols = ["C" + str(i) for i in range(1, 27)]
label_col = "Label"

header = [label_col] + nume_cols + cate_cols

all_data = pd.read_csv(filepath, sep="\t", header=None, names=header)

print('Data Shape:', all_data.shape)
print(all_data.head())

ord_encoder = ce.ordinal.OrdinalEncoder(cols=cate_cols)


def encode_csv(df, encoder, label_col, typ='fit'):
    if typ == 'fit':
        df = encoder.fit_transform(df)
    else:
        df = encoder.transform(df)
    y = df[label_col].values
    del df[label_col]
    return df, y


# split data to 3 sets
length = len(all_data)
train_data = all_data.loc[:0.8 * length - 1]
valid_data = all_data.loc[0.8 * length:0.9 * length - 1]
test_data = all_data.loc[0.9 * length:]

# 数据特征编码转换
train_x, train_y = encode_csv(train_data, ord_encoder, label_col)
valid_x, valid_y = encode_csv(valid_data, ord_encoder, label_col, 'transform')
test_x, test_y = encode_csv(test_data, ord_encoder, label_col, 'transform')

print(
    'Train Data Shape: X: {trn_x_shape}; Y: {trn_y_shape}.\nValid Data Shape: X: {vld_x_shape}; Y: {vld_y_shape}.\nTest Data Shape: X: {tst_x_shape}; Y: {tst_y_shape}.\n'
    .format(trn_x_shape=train_x.shape,
            trn_y_shape=train_y.shape,
            vld_x_shape=valid_x.shape,
            vld_y_shape=valid_y.shape,
            tst_x_shape=test_x.shape,
            tst_y_shape=test_y.shape, ))

print(train_x.head())

MAX_LEAF = 64
MIN_DATA = 20
NUM_OF_TREES = 100
TREE_LEARNING_RATE = 0.15
EARLY_STOPPING_ROUNDS = 20
METRIC = "auc"
SIZE = "sample"

params = {
    'task': 'train',
    'boosting_type': 'gbdt',
    'num_class': 1,
    'objective': "binary",
    'metric': METRIC,
    'num_leaves': MAX_LEAF,
    'min_data': MIN_DATA,
    'boost_from_average': True,
    # set it according to your cpu cores.
    'num_threads': 20,
    'feature_fraction': 0.8,
    'learning_rate': TREE_LEARNING_RATE,
}

lgb_train = lgb.Dataset(train_x, train_y.reshape(-1), params=params, categorical_feature=cate_cols)
lgb_valid = lgb.Dataset(valid_x, valid_y.reshape(-1), reference=lgb_train, categorical_feature=cate_cols)
lgb_test = lgb.Dataset(test_x, test_y.reshape(-1), reference=lgb_train, categorical_feature=cate_cols)

# 模型训练
lgb_model = lgb.train(params,
                      lgb_train,
                      num_boost_round=NUM_OF_TREES,
                      early_stopping_rounds=EARLY_STOPPING_ROUNDS,
                      valid_sets=lgb_valid,
                      categorical_feature=cate_cols)

# 测试效果
test_preds = lgb_model.predict(test_x)
auc = roc_auc_score(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
logloss = log_loss(np.asarray(test_y.reshape(-1)), np.asarray(test_preds), eps=1e-12)
res_basic = {"auc": auc, "logloss": logloss}
print(res_basic)

# ###########################################################################################
# ####  数据处理增强
import lgb_model.lightgbm_utils as lgb_utils

label_col = 'Label'
num_encoder = lgb_utils.NumEncoder(cate_cols, nume_cols, label_col)
train_x, train_y = num_encoder.fit_transform(train_data)
valid_x, valid_y = num_encoder.transform(valid_data)
test_x, test_y = num_encoder.transform(test_data)
del num_encoder
print(
    'Train Data Shape: X: {trn_x_shape}; Y: {trn_y_shape}.\nValid Data Shape: X: {vld_x_shape}; Y: {vld_y_shape}.\nTest Data Shape: X: {tst_x_shape}; Y: {tst_y_shape}.\n'
    .format(trn_x_shape=train_x.shape,
            trn_y_shape=train_y.shape,
            vld_x_shape=valid_x.shape,
            vld_y_shape=valid_y.shape,
            tst_x_shape=test_x.shape,
            tst_y_shape=test_y.shape, ))

lgb_train = lgb.Dataset(train_x, train_y.reshape(-1), params=params)
lgb_valid = lgb.Dataset(valid_x, valid_y.reshape(-1), reference=lgb_train)
lgb_model = lgb.train(params,
                      lgb_train,
                      num_boost_round=NUM_OF_TREES,
                      early_stopping_rounds=EARLY_STOPPING_ROUNDS,
                      valid_sets=lgb_valid)
test_preds = lgb_model.predict(test_x)
auc = roc_auc_score(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
logloss = log_loss(np.asarray(test_y.reshape(-1)), np.asarray(test_preds), eps=1e-12)
res_optim = {"auc": auc, "logloss": logloss}
print(res_optim)

# ###########################################################################################
# 保存模型
tmp = './_model'
os.makedirs(tmp, exist_ok=True)
save_file = os.path.join(tmp, 'finished.model')
lgb_model.save_model(save_file)

# 加载模型
loaded_model = lgb.Booster(model_file=save_file)
# eval the performance again
test_preds = loaded_model.predict(test_x)

auc = roc_auc_score(np.asarray(test_y.reshape(-1)), np.asarray(test_preds))
logloss = log_loss(np.asarray(test_y.reshape(-1)), np.asarray(test_preds), eps=1e-12)
res_basic = {"auc": auc, "logloss": logloss}
print(res_basic)

if __name__ == '__main__':
    print(os.path.abspath(os.path.dirname(__file__)))
